#!/bin/bash

DART_SOURCE_DIR='../lib/src/constants/'
KOTLIN_SOURCE_DIR='../android/src/main/kotlin/com/texture_image/constants/'
OBJC_SOURCE_DIR='../ios/Classes/Constants/'

ERR_CODE_DEFINES='../sources/error_code'
DART_SOURCE="${DART_SOURCE_DIR}error_codes.dart"
KOTLIN_SOURCE="${KOTLIN_SOURCE_DIR}ErrorCodes.kt"
OBJC_SOURCE="${OBJC_SOURCE_DIR}ErrorCodes.h"

echo "Generating error code declaration files..."

if [ ! -d "$DART_SOURCE_DIR" ]; then
  mkdir $DART_SOURCE_DIR
  chmod 777 ../lib/src/constants ../lib/src ../lib
fi

if [ ! -d "$OBJC_SOURCE_DIR" ]; then
  mkdir $OBJC_SOURCE_DIR
  chmod 777 ../ios/Classes/Constants ../ios/Classes ../ios
fi

if [ ! -f "$ERR_CODE_DEFINES" ]; then
  echo "Target definition file not exists, abort"
  exist -1
fi

function insertHeaderFileDeclaration() {
  {
    printf "/// Error code list\n///\n"
    printf "/// This file is generated by shell script on %s, please don't edit this file manually\n\n" "$(date +%Y-%m-%d)"
  } >>"$1"
}

function genDartTemplateFile() {
  # Empty this file or create if not exists
  : >"$DART_SOURCE"

  insertHeaderFileDeclaration "$DART_SOURCE"

  {
    printf "class ErrorCode {\n"
    printf "}"
  } >>"$DART_SOURCE"
}

function genKotlinTemplateFile() {
  : >"$KOTLIN_SOURCE"

  insertHeaderFileDeclaration "$KOTLIN_SOURCE"

  {
    printf "package com.texture_image.constants\n\n"
    printf "enum class ErrorCode(val code: Int) {\n"
    printf "}"
  } >>"$KOTLIN_SOURCE"
}

function genObjcTemplateFile() {
  : >"$OBJC_SOURCE"

  insertHeaderFileDeclaration "$OBJC_SOURCE"

  {
    printf "#import <Foundation/Foundation.h>\n\n"
    printf "typedef NS_ENUM(NSInteger, ErrorCode) {\n"
    printf "};"
  } >>"$OBJC_SOURCE"
}

function genTemplateFiles() {
  genDartTemplateFile   # Dart
  genKotlinTemplateFile # Kotlin
  genObjcTemplateFile   # Objc
}

function fillDartTemplateFile() {
  name=$(rejoinParamName "$2" 1 "")
  sed -i '' -e "/}/ i \\
  // $1\\
  static const $name = $3;\\
  " "$DART_SOURCE"
}

function fillKotlinTemplateFile() {
  name=$(rejoinParamName "$2" 0 "_")
  sed -i '' -e "/\}/ i \\
    // $1\\
    $name($3),\\
    " "$KOTLIN_SOURCE"
}

# Insert methods to iOS platform
function fillObjcTemplateFile() {
  name=$(rejoinParamName "$2" 1 "")
  sed -i '' -e "/};/ i \\
    // $1\\
    $name = $3,\\
    " "$OBJC_SOURCE"
}

# Re-join the parameter name with specific character
# the first param is the parameter name itself and the
#
# Second param has tow options: 0 or 1, 0 means uppercase
# all characters of each word while 1 only capitalized them
# from index 1 and on, which is same as "CamelCase" rule
#
# The third param is the character used to rejoin the array
#
# eg. rejoinParamName "hello_world" 1 "" -> helloWorld
function rejoinParamName() {
  # Join array with particular char: joinByChar , "$arr[@]"
  function joinByChar() {
    local IFS="$1"
    shift
    echo "$*"
  }

  local IFS='_'
  read -ra arr <<<"$1"

  for i in "${!arr[@]}"; do
    if [[ $2 -eq 1 ]]; then
      if [[ $i -gt 0 ]]; then
        local com="${arr[$i]}"
        arr[$i]=$(echo "${com:0:1}" | tr '[:lower:]' '[:upper:]')${com:1}
      else
        continue
      fi
    fi

    if [[ $2 -eq 0 ]]; then
      arr[$i]="$(echo "${arr[$i]}" | tr '[:lower:]' '[:upper:]')"
    fi
  done

  joinByChar "$3" "${arr[@]}"
}

function parseMethodsDefine() {
  local file="$1"

  while IFS= read -r line || [ -n "$line" ]; do
    # Trim lines and ignore comment lines
    trimmed="$(printf "%s" "$line")"
    echo "$trimmed"
    if [[ "$trimmed" == //* || -z "$trimmed" ]]; then
      continue
    fi

    echo "$trimmed"

    # Separate by space and insert into target files
    IFS="#"
    read -ra array <<<"$trimmed"

    comment=${array[1]} || ''
    assignment=${array[0]}

    # Separate assignment by =
    IFS='='
    read -ra array <<<"$assignment"

    variable=${array[0]}
    value=${array[1]}

    fillDartTemplateFile "$comment" "$variable" "$value"
    fillKotlinTemplateFile "$comment" "$variable" "$value"
    fillObjcTemplateFile "$comment" "$variable" "$value"

  done <"$file"
}

genTemplateFiles
parseMethodsDefine "$ERR_CODE_DEFINES"

echo "Error code files generated" && exit 0
